home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Mathematics / Notebooks / SigProc2.0 / Packages / SignalProcessing / Digital / ZTransform.m < prev   
Encoding:
Text File  |  1992-08-18  |  39.3 KB  |  1,184 lines

  1. (*  :Title:    z-Transform Rule Base  *)
  2.  
  3. (*  :Authors:    Brian Evans, James McClellan  *)
  4.  
  5. (*
  6.     :Summary:    To take the forward, multi-dimensional z-transform
  7.         of a discrete-time expression of mathematical
  8.         and signal processing structures.
  9.  *)
  10.  
  11. (*  :Context:    SignalProcessing`Digital`ZTransform`  *)
  12.  
  13. (*  :PackageVersion:  2.7    *)
  14.  
  15. (*
  16.     :Copyright:    Copyright 1989-1991 by Brian L. Evans
  17.         Georgia Tech Research Corporation
  18.  
  19.     Permission to use, copy, modify, and distribute this software
  20.     and its documentation for any purpose and without fee is
  21.     hereby granted, provided that the above copyright notice
  22.     appear in all copies and that both that copyright notice and
  23.     this permission notice appear in supporting documentation,
  24.     and that the name of the Georgia Tech Research Corporation,
  25.     Georgia Tech, or Georgia Institute of Technology not be used
  26.     in advertising or publicity pertaining to distribution of the
  27.     software without specific, written prior permission.  Georgia
  28.     Tech makes no representations about the suitability of this
  29.     software for any purpose.  It is provided "as is" without
  30.     express or implied warranty.
  31.  *)
  32.  
  33. (*  :History:    *)
  34.  
  35. (*  :Keywords:    z-transform, region of convergence    *)
  36.  
  37. (*
  38.     :Source:        Muth, E. J. {Transform Methods}.  1977
  39.  
  40.             Oppenheim and Schafer.  {Digital Signal Processing}. 1973.
  41.  
  42.               Clements, M., and Pease, J.  "On Causal Linear Phase IIR
  43.         Digital Filters". Transactions of Acoustics, Speech, and
  44.         Signal Processing (ASSP).  April 1989
  45.  
  46.             Dungeon and Mersereau.  {Multidimensional Signal
  47.         Processing}. 1984.
  48.  *)
  49.  
  50. (*
  51.     :Warning:    This package stuff is nasty; reminds me of Lisp, except
  52.           that Lisp had package-independent keywords like  :hi.
  53.           Remember,  that only those symbols with a ::usage are
  54.           exported.
  55.         Keep all conditional clauses on the same line; breaking
  56.           long clauses  onto  separate  lines with RETURNS will
  57.           cost you (package context is not reset to Global)
  58.         I do rely  on  three  variables that are global only to
  59.           this package--  completeOptions, dialogueAllFlag, and
  60.           generatePairsFlag.  The first maintains a list of the
  61.           complete set of options.  The  second  specifies  the
  62.           level of dialogue. The third indicates whether or not
  63.           to simplify the resulting transform. I'm really sorry
  64.           for doing this--- I know that it is bad programming.
  65.  *)
  66.  
  67. (*  :Mathematica Version:  1.2 or 2.0  *)
  68.  
  69. (*  :Limitation:  *)
  70.  
  71. (*  :Discussion:  All new functions have usage information.
  72.           Local state rules base with a total of 76 rules:
  73.             I.   multidimensional hooks         9 rules
  74.             II.  rational transforms        15 rules
  75.             III. non-rational transform pairs     7 rules
  76.             IV.  transform properties        13 rules
  77.             V.   transforms of DSP structures    22 rules
  78.             VI.  transform strategies        10 rules
  79.  
  80.     The only purpose to the multidimensional hook rules is to track
  81.     the region of convergence for non-separable functions.  Without
  82.     these rules, the  z-transform  rule  base  would still properly
  83.     compute the z-transform function.   Otherwise, the DTFTransform
  84.     would not work properly for functions  like  (6/7)^n1 (9/10)^n2
  85.     Impulse[n1 - n2] Step[n1, n2]  with respect to the variables n1
  86.     and n2.
  87.  
  88.     At each step in the z-transform rules base, the current expression
  89.     has a local state associated with it.  This state consists of
  90.     a list of five boolean values.  Each boolean value is associated
  91.     with a strategy.  If an element is True, then that strategy has not
  92.     been tried yet; if False, then that strategy has already been tried,
  93.     and it will not be tried again.  Thus, local state is used to
  94.     prevent infinite loops which would be caused by the repetitive
  95.     application of certain strategy rules.  See the section  S T A T E
  96.     D E F I N I T I O N  below and see section VI of the rules.
  97.  
  98.     MyZTransform[ f[n], n, z, state, nlist, zlist, options ] is similar
  99.     to ZTransform.  The one-dimensional z-transform of f[n] will be
  100.     returned as a list of three pieces of data:  X(z), Rminus, Rplus.
  101.     The current dimension being transformed is indicated by atoms n
  102.     and z; nlist contains the list of all time index variables
  103.     used in f[n]; and zlist contains the z-transform variables.
  104.     Note that ZTransform drives the rule base defined by MyZTransform
  105.     when computing the forward z-transform.
  106.  
  107.     multidROC[zexpr, oldzexpr] accumulates region of convergence
  108.     information.  That is, ROC of the current z-transform is only
  109.     one-dimensional; therefore, zexpr must be updated with the
  110.     cumulative ROC information in oldzexpr.
  111.  *)
  112.  
  113.  
  114. (*  :Functions:  ZTransform  *)
  115.  
  116.  
  117.  
  118. (*  B E G I N     P A C K A G E  *)
  119.  
  120. BeginPackage[ "SignalProcessing`Digital`ZTransform`",
  121.           "SignalProcessing`Digital`ZSupport`",
  122.           "SignalProcessing`Support`TransSupport`",
  123.           "SignalProcessing`Support`ROC`",
  124.           "SignalProcessing`Support`FilterSupport`",
  125.           "SignalProcessing`Support`SigProc`",
  126.           "SignalProcessing`Support`SupCode`" ]
  127.  
  128.  
  129. If [ TrueQ[ $VersionNumber >= 2.0 ],
  130.      Off[ General::spell ];
  131.      Off[ General::spell1 ] ];
  132.  
  133.  
  134. (*  U S A G E     I N F O R M A T I O N  *)
  135.  
  136. ZTransform::usage =
  137.     "ZTransform[e,n] or ZTransform[e,n,z] gives the z-transform of \
  138.     the expression e, which is a function of n, by returning an object \
  139.     of three slots which is tagged by ZTransData: \
  140.     <z-transform>, <rminus>, <rplus>, and <z-variables>. \
  141.     The Region of Convergence (ROC) is <rminus> < |z| < <rplus>. \
  142.     Note that the returned ROC is either the actual ROC or a subset \
  143.     of the actual ROC. \
  144.     In two dimensions, ZTransform[e, {n1, n2}, {z1, z2}], is the same as \
  145.     ZTransform [ ZTransform [e, n1, z1], n2, z2 ]. \
  146.     This notation extends naturally to higher dimensions."
  147.  
  148. (*  E N D     U S A G E     I N F O R M A T I O N  *)
  149.  
  150.  
  151. Begin[ "`Private`" ]
  152.  
  153.  
  154. (*  M E S S A G E S  *)
  155.  
  156. ZTransform::notexist =
  157.     "The function `` does not have a valid z-transform with respect to ``."
  158.  
  159. ZTransform::badROC = "Improper region of convergence in ``." 
  160.  
  161.  
  162. (*  U S E R     I N T E R F A C E  *)
  163.  
  164. (*  Z Operator  *)
  165. Unprotect[Z]
  166. Z/: TheFunction[ Z[n_, z_][f_] ] := ZTransform[f, n, z]
  167. Protect[Z]
  168.  
  169. (*  ZTransform  *)
  170. ZTransform/: Options [ ZTransform ] :=
  171.     { Definition -> False, Dialogue -> True,
  172.       Simplify -> True, TransformLookup -> {} }
  173.  
  174. ZTransform[f_] :=
  175.     ztransformdriver[ Options[ZTransform], f ]
  176. ZTransform[f_, n_] :=
  177.     ztransformdriver[ Options[ZTransform], f, n ]
  178. ZTransform[f_, n_, z_] :=
  179.     ztransformdriver[ Options[ZTransform], f, n, z ]
  180. ZTransform[f_, n_, z_, op__] :=
  181.     ztransformdriver[ ToList[op] ~Join~ Options[ZTransform], f, n, z ]
  182.  
  183. (*  data global to only this package, see :Warning: above *)
  184. completeOptions = {}
  185. dialogueAllFlag = False
  186. indentationString = ""
  187. simplifyFlag = False
  188.  
  189. (*  validvarQ  *)
  190. validvarQ[ x_Symbol ] := True
  191. validvarQ[ x_List ] := Apply[And, Map[VariableQ, x]]
  192. validvarQ[ x_ ] := False
  193.  
  194. (*  Interface support  *)
  195. ztransformdriver[op_, f_, n_, rest___] :=
  196.     Message[ Transform::badvar, "discrete-time", ZTransform, n ] /;
  197.     ! validvarQ[n]
  198.  
  199. ztransformdriver[op_, f_, n_, z_] :=
  200.     Message[ Transform::badvar, "z", ZTransform, z ] /;
  201.     ! validvarQ[z]
  202.  
  203. ztransformdriver[op_, f_, n_, z_] :=
  204.     Block [ {},
  205.  
  206.         (* Set all global variables right here *)
  207.         completeOptions = op;
  208.         dialogueAllFlag = SameQ[Replace[Dialogue, op], All];
  209.         simplifyFlag = TrueQ[Replace[Simplify, op]];
  210.  
  211.         (* Do the transform  *)
  212.         cleanup [ ztransform[op, f, n, z], InformUserQ[op] ] ]
  213.  
  214. ztransform[op_, args__] :=
  215.     Replace [ ztrans[op, args], ZTransformInterfaceRules ]
  216.  
  217. ZTransformInterfaceRules = {
  218.     ztrans[op_, e_] :> e        /; ZTransformQ[e],
  219.  
  220.     ztrans[op_, e_] :>
  221.         Message[Transform::novariables, "n (time)", GetVariables[e]],
  222.  
  223.     ztrans[op_, e_, n_] :> e    /; ZTransformQ[e],
  224.  
  225.     ztrans[op_, e_, n_] :>
  226.         ztransform[op, e, n, DummyVariables[Length[n], Global`z]],
  227.  
  228.     ztrans[op_, e_, n_, zl_] :>
  229.         MultiDTransform[ MakeZObject, ztransform,
  230.                  ZTransformQ, e, n, z, zl, op ] /;
  231.         ListQ[n] && ( AtomQ[zl] || ListQ[zl] ),
  232.  
  233.     ztrans[op_, e_, n_, z_] :> ztransform[op, e, n, z, {n}, {z}] /;
  234.         AtomQ[n] && AtomQ[z],
  235.  
  236.     ztrans[op_, e_, n_, z_, nlist_, zlist_] :>
  237.         If [ SameQ[ToList[ZVariables[e]], zlist],
  238.              e,
  239.              multidROC[ztransform[op, TheFunction[e], n, z, nlist, zlist],
  240.                    e] ] /;
  241.         ZTransformQ[e] && AtomQ[n] && AtomQ[z],
  242.  
  243.     ztrans[op_, e_, n_, z_, nlist_, zlist_] :>
  244.         MakeZObject[ MyZTransform [ e, n, z, nlist, zlist, op ], z ] /;
  245.         ! ZTransformQ[e] && AtomQ[n] && AtomQ[z]
  246. }
  247.  
  248. (*  cleanup passes every subexpression of the transform through explain  *)
  249. cleanup[Null, flag_] := flag
  250.  
  251. cleanup[trans_, dialogue_] :=
  252.     Block [    {dialflag, rminus, rplus, trace, valid, validROC = True},
  253.         dialflag = InformUserQ[dialogue];
  254.         trace = SameQ[dialogue, All];
  255.         valid = SameQ[Head[trans], ZTransData];
  256.         If [ valid,
  257.              rminus = SPSimplify[ GetRMinus[trans] ];
  258.              rplus = SPSimplify[ GetRPlus[trans] ];
  259.              validROC = Apply[And,
  260.                       Thread[ToList[rminus] < ToList[rplus]]] ];
  261.         Which [ TrueQ[! validROC],
  262.                   Message[ZTransform::badROC, trans],
  263.             valid && simplifyFlag,
  264.               SPSimplify[ trans, Dialogue -> trace ],
  265.             dialflag && ! valid,
  266.               Scan[explain, trans, Infinity];
  267.               trans,
  268.             True,
  269.               trans ] ]
  270.  
  271. (*  explain tells the user about those parts of the  *)
  272. (*  "time"-function which do not have a transform.   *)
  273. explain[ forwardz[f_, n_, rest__] ] :=
  274.     Message[ Transform::incomplete, "forward z-transform", f, n ]
  275.  
  276.  
  277. (*  S U P P O R T I N G     R O U T I N E S  *)
  278.  
  279. absDialogue[f_, n_, options_] :=
  280.     Block [    {dialogue, result},
  281.         dialogue = InformUserQ[options];
  282.         result = ( f /. {Abs[a_. n] :> Abs[a] n} ) Step[n] +
  283.              ( f /. {Abs[b_. n] :> - Abs[b] n} ) Step[-n - 1];
  284.  
  285.         If [ dialogue,
  286.              Print[ "( after rewriting the two-sided expression" ];
  287.              Print[ "  ", f ];
  288.              Print[ "  as a left-sided plus a right sided sequence" ];
  289.              Print[ "  ", result, " )" ] ];
  290.  
  291.         result ]
  292.  
  293. addZ[t1_, t2_] := AddT[ZForm, t1, t2]
  294.  
  295. allROC[t_] := Transform[TheFunction[t], 0, Infinity] /; ZForm[t]
  296.  
  297. antiCausalZ[t_, z_] :=
  298.     Transform[ TheFunction[t] /. z -> z^-1,
  299.            1 / GetRPlus[t], 1 / GetRMinus[t] ] /;
  300.     ZForm[t]
  301.  
  302. applyDefinition[x_, n_, z_, s_, nlist_, zlist_, op_] :=
  303.         Block [ {newx, state, summhead, trans},
  304.         state = SetStateField[s, definitionfield, False];
  305.                 summhead = If [ TrueQ[ $VersionNumber >= 2.0 ],
  306.                 Needs[ "Algebra`SymbolicSum`" ];
  307.                 Algebra`SymbolicSum,
  308.                 Needs[ "Algebra`GosperSum`" ];
  309.                 Algebra`GosperSum ];
  310.         newx = ToDiscrete [ TheFunction[x] ];
  311.         trans = summhead[newx z^(-n), {n, -Infinity, Infinity}];
  312.         If [ SameQ[Head[trans], summhead],
  313.              forwardz[x, n, z, state, nlist, zlist, op],
  314.              TransformDialogue[ Definition, op, summhead, x,
  315.                     Transform[trans, 0, Infinity] ] ] ]
  316.  
  317. computeDownsamplingFactor[f_, n_] := Numerator[ ScalingFactor[f, n] ]
  318.  
  319. conjZ[t_, z_] := ConjT[ZForm, t, z]
  320.  
  321. convolveZ[convop_, t1_, t2_] := ConvolveT[ZForm, convop, t1, t2]
  322.  
  323. (*  diagonalResamplingMatrixQ  *)
  324. diagonalResamplingMatrixQ[mat_] := False  /; ! MatrixQ[mat]
  325. diagonalResamplingMatrixQ[mat_] :=
  326.     Block [ {cond = False, diag, dims, i},
  327.         dims = Dimensions[mat];
  328.         If [ dims[[1]] == dims[[2]],
  329.              diag = Table[ mat[[i,i]], { i, 1, dims[[1]] } ];
  330.              cond = Apply[And, Map[isinteger, diag] ] &&
  331.                 SameQ[mat, DiagonalMatrix[diag]] ];
  332.         cond ]
  333.  
  334.  
  335. downsampledTransform[trans_, z_, m_] :=
  336.     Block [    {fztrans, k},
  337.         fztrans = trans /. z -> ( Exp[-2 Pi I k / m] z^(1/m) );
  338.         If [ IntegerQ[m],
  339.              1/Abs[m] Sum[fztrans, {k, 0, Abs[m]-1}],
  340.              k = Unique["k"];
  341.              1/Abs[m] Summation[k, 0, Abs[m]-1, 1][fztrans] ] ]
  342.  
  343. downsampleZ[ztrans_, z_Symbol, m_] :=
  344.     Block [    {fz, fztrans, k, rm, rp},
  345.         rm = takeRealPower[ GetRMinus[ztrans], m ];
  346.         rp = takeRealPower[ GetRPlus[ztrans], m ];
  347.         fz = downsampledTransform[ TheFunction[ztrans], z, m ];
  348.         Transform[fz, rm, rp] ] /;
  349.     ZForm[ztrans]
  350.  
  351. dz[t_, z_:Global`z, k_:1] := 
  352.     Transform[ D[TheFunction[t], {z, k}], GetRMinus[t], GetRPlus[t] ] /;
  353.     ZForm[t]
  354.  
  355. (*  fixUp: removes TransformLookup option from passed options  *)
  356. fixUp[ op_ ] :=
  357.     { Definition -> Replace[Definition, op],
  358.       Dialogue -> Replace[Dialogue, op],
  359.       Simplify -> Replace[Simplify, op] }
  360.  
  361. integrateZ[t_, z_:Global`z] := IntegrateT[ZForm, t, z, z, Infinity]
  362.  
  363. isinteger[x_] := Implies[ NumberQ[x], IntegerQ[x] ]
  364.  
  365. isintegerMatrix[ x_ ] :=
  366.     MatrixQ[x] && Apply[ SameQ, Dimensions[x] ] && 
  367.     Apply[ And, Map[isinteger, Flatten[x]] ]
  368.  
  369. lineImpulseMDZ[t_, z_, zlist_, nleft_] :=
  370.     LineImpulsemDT[ZForm, t, z, zlist, nleft, Times]
  371.  
  372. (*  mDresamplingCheck  *)
  373. mDresamplingCheck[separable, l_, n_, nvars_, nlist_] :=
  374.     MyFreeQ[l, nvars] && SubsetQ[{n}, nvars, nlist] &&
  375.       diagonalResamplingMatrixQ[l]
  376.  
  377. mDresamplingCheck[Downsample, l_, n_, nvars_, nlist_] :=
  378.     Block [    {cond},
  379.         cond = MyFreeQ[l, nvars] && SubsetQ[{n}, nvars, nlist] &&
  380.             MatrixQ[l] && Apply[SameQ, Dimensions[l]] &&
  381.             Apply[ And, Map[IntegerQ, Flatten[l]] ];
  382.         If [ cond, Needs[ "SignalProcessing`Digital`MDZTransform`" ] ];
  383.         cond ]
  384.  
  385. mDresamplingCheck[Upsample, l_, n_, nvars_, nlist_] :=
  386.     Block [ {cond},
  387.         cond = MyFreeQ[l, nvars] && SubsetQ[{n}, nvars, nlist] &&
  388.             isintegerMatrix[l];
  389.         If [ cond, Needs[ "SignalProcessing`Digital`MDZTransform`" ] ];
  390.         cond ]
  391.  
  392. multZ[t1_, t2_] := MultT[ZForm, t1, t2]
  393.  
  394. multiplyByExponential[t_, aexp_, z_, c_, options_] :=
  395.     Block [    {newrplus, rplus},
  396.         rplus = GetRPlus[t];
  397.         newrplus = If [ InfinityQ[rplus], Infinity, Abs[aexp] rplus ];
  398.         Transform[ c TheFunction[t] /. z -> z / aexp,
  399.                Abs[aexp] GetRMinus[t], newrplus ] ] /;
  400.     ZForm[t]
  401.  
  402. myZmultinomialLeftOver[f_, nvars__] :=
  403.     myZmultinomialSupport[Apply[Times, Map[Factorial, {nvars}]^-1], f] [[2]]
  404.  
  405. myZmultinomialQ[f_, nvars__] :=
  406.     TrueQ [ myZmultinomialSupport[Apply[Times, Map[Factorial, {nvars}]^-1], f] [[1]] ]
  407.  
  408. myZmultinomialSupport[factexpr_, f_. factexpr_] := { True, f }
  409.  
  410. propagateOperator[ trans_, op_ ] :=
  411.     Transform[ op[ TheFunction[trans] ],
  412.            GetRMinus[trans],
  413.            GetRPlus[trans] ] /;
  414.     ZForm[trans]
  415.  
  416. reallyDownsampledQ[f_, n_] :=
  417.     Block [    {downfact},
  418.         downfact = computeDownsamplingFactor[f, n];
  419.         (! SameQ[downfact, 0]) && (! SameQ[downfact, 1]) &&
  420.           Implies[ NumberQ[downfact], IntegerQ[downfact] ] ]
  421.  
  422. SetAttributes[rootROC, {Listable}]
  423. rootROC[x_, 0, z_] := z
  424. rootROC[x_, y_, z_] := takeRealPower[x, 1/y]
  425.  
  426. scaleZ[t_, c_] := ScaleT[ZForm, t, c]
  427.  
  428. substituteforZ[t_, z_, newz_] := SubstituteForT[ZForm, t, z, newz]
  429.  
  430. subZ[t1_, t2_] := SubT[ZForm, t1, t2]
  431.  
  432. (* takeRealPower --  assume that both arguments are real-valued *)
  433. SetAttributes[ takeRealPower, { Listable } ]
  434. takeRealPower[ 0, r_ ] := 0
  435. takeRealPower[ Infinity, r_ ] := Infinity
  436. takeRealPower[ x_^b_, r_ ] := x^(b r) /; IntegerQ[b r]
  437. takeRealPower[ x_, r_ ] := x^r
  438.  
  439. upsampleZ[ztrans_, z_Symbol, m_] :=
  440.     Block [    {fz, rm, rp},
  441.         rm = rootROC[ GetRMinus[ztrans], m, 1 ];     (* adjust ROC *)
  442.         rp = rootROC[ GetRPlus[ztrans], m, 1 ];
  443.         fz = TheFunction[ztrans] /. z -> z^m;  (* adjust transform *)
  444.         Transform[fz, rm, rp] ] /;
  445.     ZForm[ztrans] 
  446.  
  447. Zdz[t_, z_:Global`z, k_:1] := 
  448.     Block [    {count, expr},
  449.         expr = TheFunction[t];
  450.         For [ count = 0, count < k, count++,
  451.               expr = - z SPSimplify[D[expr, z]] ];
  452.         Transform[ expr, GetRMinus[t], GetRPlus[t] ] ] /;
  453.     ZForm[t] && IntegerQ[k] && ( k >= 0 )
  454.  
  455.  
  456. (*  R E G I O N     O F     C O N V E R G E N C E  *)
  457.  
  458. multidROC[zexpr_, oldz_] :=
  459.     MakeZObject[ {    zexpr[[1]],
  460.             Append[ ToList[ GetRMinus[oldz]  ], GetRMinus[zexpr] ],
  461.             Append[ ToList[ GetRPlus[oldz]   ], GetRPlus[zexpr] ] },
  462.              Append[ ToList[ZVariables[oldz]], ZVariables[zexpr] ] ] /;
  463.     ZTransformQ[zexpr] && ZTransformQ[oldz]
  464.  
  465.  
  466. (*  S T A T E     D E F I N T I O N  *)
  467.  
  468.     (* in the order of their appearance in the rule base  *)
  469.  
  470. factorfield = 1            (* apply Factor[] to denominator    *)
  471. expandfield = 2            (* apply Expand[] to expression        *)
  472. expandallfield = 3        (* apply ExpandAll[] to expression    *)
  473. stepfield = 4            (* multiply by (Step[n] + Step[-n - 1])    *)
  474. thefunfield = 5            (* apply TheFunction to expression    *)
  475. definitionfield = 6        (* apply the z-transform definition    *)
  476.  
  477. statevariables = 6
  478.  
  479. initZstate[] := Table[True, {statevariables}]
  480.  
  481.  
  482. (*  B E G I N     R U L E     B A S E  *)
  483.  
  484. (*  MyZByPass--- called by forward DTFT and interfaces to MyZTransform  *)
  485. MyZByPass[ f_, n_, z_, nlist_, zlist_, op_ ] :=
  486.     Block [ {trans},
  487.         completeOptions = op;
  488.         dialogueAllFlag = SameQ[Replace[Dialogue, op], All];
  489.         indentationString = "  ";
  490.         simplifyFlag = TrueQ[ Replace[Simplify, op] ];
  491.         trans = MyZTransform[f, n, z, initZstate[], nlist, zlist, op];
  492.         MakeZObject[ trans, z ] ]
  493.  
  494. (*  Interface to MyZTransform from ztransformdriver  *)
  495. MyZTransform[ f_, n_, z_, nlist_, zlist_, op_ ] :=
  496.     MyZTransform[ f, n, z, initZstate[], nlist, zlist, op ]
  497.  
  498. (*   Driver for one-dimensional rule base            *)
  499. (*   Loop until the expression to be transformed doesn't change *)
  500. MyZTransform[ f_, n_, z_, s_, nlist_, zlist_, op_ ] :=
  501.     Block [ {discretef, laste, newe, newop, newzrules},
  502.  
  503.         (* make f discrete *)
  504.         discretef = ToDiscrete[ f /. CStep[a_. n] :> Step[n] ];
  505.  
  506.         (* generate the z-transform rules *)
  507.         newzrules = TransformFixUp[ n, z, op, forwardz, True,
  508.                         ZTransform, 0, Infinity ];
  509.         ZTransformRules = Join[ newzrules,
  510.                     OriginalZTransformRules ];
  511.  
  512.         (* take the 1-D transform-- dialogueAllFlag is global  *)
  513.         newop = fixUp[op];
  514.         newe = forwardz[discretef, n, z, s, nlist, zlist, newop];
  515.         While [ ! SameQ[ laste, newe ],
  516.             If [ dialogueAllFlag,
  517.                  Print[ indentationString, newe ];
  518.                  Print[ indentationString, "which becomes" ] ];
  519.             laste = newe;
  520.             newe = laste /. ( forwardz[a__] :>
  521.                  Replace[forwardz[a], ZTransformRules ] ) ];
  522.         If [ dialogueAllFlag, Print[ indentationString, newe ] ];
  523.  
  524.         newe ]
  525.  
  526.  
  527. (* Format intermediate forms so that output from Dialogue -> All is readable *)
  528.  
  529. Format[ antiCausalZ[t_, z_] ] :=
  530.     SequenceForm[ {t}, Subscript[z -> z^-1], Subscript[" and flip ROC "] ]
  531.  
  532. Format[ downsampleZ[t_, z_, m_, ___] ] :=
  533.     SequenceForm[ {t},
  534.               Subscript[" resample (ROC expands) "] ]
  535.  
  536. Format[ dz[t_, z_:Global`z, k_:1] ] := 
  537.     SequenceForm[ ColumnForm[ {"D" Superscript[k],
  538.                    "  " ~StringJoin~ ToString[z]} ],
  539.               { t } ]
  540.  
  541. Format[ forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] ] := 
  542.     SequenceForm[ ColumnForm[{"Z",
  543.                   "  " ~StringJoin~ ToString[n]}],
  544.               { x } ]
  545.  
  546. Format[ multiplyByExponential[t_, aexp_, z_, c_, options_] ] :=
  547.     c SequenceForm[ {t},
  548.             Subscript[z -> z / aexp],
  549.             Subscript[" and scale ROC "] ]
  550.  
  551. Format[ propagateOperator[ztrans_, op_] ] := op [ ztrans ]
  552.  
  553. Format[ upsampleZ[t_, z_, m_, ___] ] :=
  554.     SequenceForm[ {t},
  555.               Subscript[" resample (ROC shrinks) "] ]
  556.  
  557. Format[ Zdz[t_, z_:Global`z, k_:1] ] := 
  558.     SequenceForm[ ColumnForm[ {"Zdz" Superscript[k],
  559.                    "    " ~StringJoin~ ToString[z]} ],
  560.               { t } ]
  561.  
  562.  
  563. (*  B E G I N     R U L E S  *)
  564.  
  565.  
  566. ZTransformRules = {}
  567.  
  568. OriginalZTransformRules = {
  569.  
  570.  
  571. (*  I.    M U L T I D I M E N S I O N A L     H O O K S            *)
  572.  
  573.  
  574. (*      A.  Region of convergence specification for dimension given    *)
  575. (*          by the variable n.  Allows multi-dimensional z-transforms    *)
  576. (*          like a^n1 Impulse[n1 - n2] Step[n1,n2] to be taken --    *)
  577. (*          see definition for LineImpulsemDT in "TransSupport.m"    *)
  578. forwardz[ SignalProcessing`ROCinfo[n_, rm_:0 , rp_:Infinity], n_, z_,
  579.         s_, nlist_, zlist_, op_ ] :>
  580.     Transform[ 1, rm, rp ],
  581.  
  582.  
  583. (*      B.  Multidimensional line Impulses become LineImpulses.    *)
  584. forwardz[ f_. Impulse[k_. n1_Symbol + l_. n2_Symbol], n_, z_,
  585.         s_, nlist_, zlist_, op_ ] :>
  586.     forwardz[ f LineImpulse[{n1,n2}, {k,-l}],
  587.               n, z, s, nlist, zlist, op ] /;
  588.     SubsetQ[{n1, n2}, nlist] && MemberQ[{n1, n2}, n],
  589.  
  590.  
  591. (*      C.  Line impulses.                        *)
  592. forwardz[ f_. LineImpulse[varlist_, coefflist_], n_, z_,
  593.         s_, nlist_, zlist_, op_ ] :>
  594.     Block [    {functionofn, zlistmD},
  595.         functionofn = f /. varlist ~ReplaceWith~ (n / coefflist);
  596.         zlistmD = AssociateItem[varlist, nlist, zlist];
  597.         lineImpulseMDZ[forwardz[functionofn, n, z, s, nlist, zlist, op], z, zlistmD, Complement[varlist,{n}]] ] /;
  598.     FreeQ[f, LineImpulse[a__]],
  599.  
  600.  
  601. (*      D.  Multinomials                        *)
  602. forwardz[ f_. Multinomial[n1_, nvars__], n_, z_, s_, nlist_, zlist_, op_ ] :>
  603.     Block [    {newfun},
  604.         simplifyFlag = True;     (* data global to this package *)
  605.         newfun = f Binomial[Plus[n1, nvars],
  606.                     Apply[Times, Complement[{n1, nvars},{n}]]];
  607.         forwardz[newfun, n, z, s, nlist, zlist, op] ] /;
  608.     SubsetQ[{n1, nvars}, nlist] && MemberQ[{n1, nvars}, n],
  609.  
  610. forwardz[ f_ (Plus[n1_, nvars__])!, n_, z_, s_, nlist_, zlist_, op_ ] :>
  611.     forwardz[ myZmultinomialLeftOver[f, n1, nvars] Multinomial[n1, nvars],
  612.           n, z, s, nlist, zlist, op ] /;
  613.     SubsetQ[{n1, nvars}, nlist] && myZmultinomialQ[f, n1, nvars],
  614.  
  615.  
  616. (*      E.  Resampling                        *)
  617. (*          1. Upsampling                        *)
  618. forwardz[ Upsample[l_, nvars_List][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  619.         Block [ {dim, expr, i},
  620.         dim = Length[nvars];
  621.         expr = f;
  622.         For [ i = 1, i <= dim, i++,
  623.               expr = Upsample[ l[[i,i]], nvars[[i]] ][expr] ];
  624.         forwardz[ expr, n, z, s, nlist, zlist, op ] ] /;
  625.     mDresamplingCheck[separable, l, n, nvars, nlist],
  626.  
  627. forwardz[ Upsample[l_, nvars_List][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  628.     upsampleSetUp[ l, nvars, f, n, z, s, nlist, zlist, op ] /;
  629.     mDresamplingCheck[Upsample, l, n, nvars, nlist],
  630.  
  631.  
  632. (*          2. Downsampling                        *)
  633. forwardz[ Downsample[m_, nvars_List][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  634.         Block [ {dim, expr, i},
  635.         dim = Length[nvars];
  636.         expr = f;
  637.         For [ i = 1, i <= dim, i++,
  638.               expr = Downsample[ m[[i,i]], nvars[[i]] ][expr] ];
  639.         forwardz[ expr, n, z, s, nlist, zlist, op ] ] /;
  640.     mDresamplingCheck[separable, m, n, nvars, nlist],
  641.  
  642. forwardz[ Downsample[m_, nvars_List][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  643.     downsampleSetUp[ m, nvars, f, n, z, s, nlist, zlist, op ] /;
  644.     mDresamplingCheck[Downsample, m, n, nvars, nlist],
  645.  
  646.  
  647.  
  648.  
  649. (*  II.   R A T I O N A L     Z - T R A N S F O R M S            *)
  650.  
  651.  
  652. (*      A.  Lookup rules for the zero, step, and impulse functions.    *)
  653. forwardz[ 0, n_, z_, s_, nlist_, zlist_, op_ ] :>
  654.     Transform[ 0, 0, Infinity ],
  655.  
  656. forwardz[ Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  657.     Transform[ 1 / ( 1 - z^-1 ), 1, Infinity ],
  658.  
  659. forwardz[ Pulse[L_, n_ + n0_.], n_, z_, s_, nlist_, zlist_, op_ ] :>
  660.     Transform[ z^n0 ( 1 - z^(-L) ) / ( 1 - z^-1), 0, Infinity ] /;
  661.     FreeQ[L, n] && FreeQ[n0, n],
  662.  
  663. forwardz[ a_. ( Step[n_ + b_.] - Step[n_ + c_.] ), n_, z_,
  664.         s_, nlist_, zlist_, op_ ] :>
  665.     allROC[subZ[forwardz[a Step[n + b], n, z, s, nlist, zlist, op],
  666.             forwardz[a Step[n + c], n, z, s, nlist, zlist, op]]] /;
  667.     ( b > c ),
  668.  
  669. forwardz[ a_. Step[n_ + b_.] - a_. Step[n_ + c_.] + rest_, n_, z_,
  670.         s_, nlist_, zlist_, op_ ] :>
  671.     addZ[allROC[subZ[forwardz[a Step[n + b], n, z, s, nlist, zlist, op],
  672.              forwardz[a Step[n + c], n, z, s, nlist, zlist, op]]],
  673.          forwardz[rest, n, z, s, nlist, zlist, op]] /;
  674.     ( b > c ),
  675.  
  676. forwardz[ a_. Impulse[n_ + n0_.], n_, z_, s_, nlist_, zlist_, op_ ] :>
  677.     Transform[ (a /. n -> -n0 ) z^n0, 0, Infinity ],
  678.  
  679.  
  680. (*      B.  Sinusoidal functions                    *)
  681. forwardz[ Sin[b_. + w_. n_] Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  682.     Transform[ ( Sin[b] + Sin[w - b] z^-1 ) /
  683.            ( 1 - 2 Cos[w] z^-1 + z^-2 ), 1, Infinity ] /;
  684.      FreeQ[{b,w}, n],                    (*  [Muth, 361]  *)
  685.  
  686. forwardz[ Cos[b_. + w_. n_] Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  687.     Transform[ ( Cos[b] - Cos[w - b] z^-1 ) /
  688.            ( 1 - 2 Cos[w] z^-1 + z^-2 ), 1, Infinity ] /;
  689.      FreeQ[{b,w}, n],                    (*  [Muth, 361]  *)
  690.  
  691. forwardz[ Sinh[b_. + w_. n_] Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  692.     Transform[ ( Sinh[b] + Sinh[w - b] z^-1 ) /
  693.            ( 1 - 2 Cosh[w] z^-1 + z^-2 ), 1, Infinity ] /;
  694.      FreeQ[{b,w}, n],                    (*  [Muth, 361]  *)
  695.  
  696. forwardz[ Cosh[b_. + w_. n_] Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  697.     Transform[ ( Cosh[b] - Cosh[w - b] z^-1 ) /
  698.            ( 1 - 2 Cosh[w] z^-1 + z^-2 ), 1, Infinity ] /;
  699.      FreeQ[{b,w}, n],                    (*  [Muth, 361]  *)
  700.  
  701.  
  702. (*      C.  Binomial forms                        *)
  703. forwardz[ Binomial[n_, k_] Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  704.     Block [ {},
  705.         Assuming[ k > 0, dialogueAllFlag ];
  706.         Transform[ z^-k / (1 - z^-1)^(k + 1), 1, Infinity ] ] /;
  707.     FreeQ[k, n] && Implies[NumberQ[k], (k > 0)],         (* [Muth, 358] *)
  708.  
  709. forwardz[ Binomial[k_, n_] a_^n_ b_^(k_ - n_) Step[n_], n_, z_,
  710.         s_, nlist_, zlist_, op_ ] :>
  711.     Block [ {},
  712.         Assuming[ k > 0, dialogueAllFlag ];
  713.         Transform[ ( a z^-1 + b ) ^ k, -a/b, Infinity ] ] /;
  714.     FreeQ[{a,b,k}, n] && Implies[NumberQ[k], (k > 0)],    (* [Muth, 358] *)
  715.  
  716.  
  717. (*      D.  Expand definitions of multinomial forms            *)
  718. forwardz[ f_ Multinomial[n_, r___], n_, z_, s_, nlist_, zlist_, op_ ] :>
  719.     Block [    {expandr, rlist},
  720.         rlist = If [ EmptyQ[List[r]], {0}, ToList[r] ];
  721.         expandr = Apply[ Times, Map[Factorial, rlist] ];
  722.         forwardz [ f Plus[n, r] / ( n! expandr ), n, z,
  723.                s, nlist, zlist, op ] ] /;
  724.     FreeQ[{r}, n],
  725.  
  726.  
  727. (*      E.  Hybrid binomial/multinomial forms                *)
  728. forwardz[ (n_ + k_ + j_.)! Step[n_] / n_!, n_, z_, s_, nlist_, zlist_, op_ ] :>
  729.     Block [ {},
  730.         Assuming[ k > 0, dialogueAllFlag ];
  731.         Transform[ z^j k! / ( 1 - z^-1 )^(k + 1), 1, Infinity ] ] /;
  732.     FreeQ[{k,j}, n] && Implies[NumberQ[k], (k > 0)],    (*  ????  *)
  733.  
  734. forwardz[ Binomial[n_ + k_ + j_., k_] Step[n_], n_, z_,
  735.         s_, nlist_, zlist_, op_ ] :>
  736.     Block [ {},
  737.         Assuming[ k > 0, dialogueAllFlag ];
  738.         Transform[ z^j / ( 1 - z^-1 )^(k + 1), 1, Infinity ] ] /;
  739.     FreeQ[{k,j}, n] && Implies[NumberQ[k], (k > 0)],    (*  ????  *)
  740.  
  741.  
  742.  
  743.  
  744. (*  III. N O N - R A T I O N A L     Z - T R A N S F O R M S        *)
  745.  
  746.  
  747. (*      A.  Denominators are rational functions of n            *) 
  748. forwardz[ Step[n_] / n_!, n_, z_, s_, nlist_, zlist_, op_ ] :>
  749.     Transform[ Exp[z^-1], 0, Infinity ],            (*  [Muth, 363]  *)    
  750.  
  751. forwardz[ Step[n_] / ( a_ n_ + b_ ), n_, z_, s_, nlist_, zlist_, op_ ] :>
  752.     scaleZ[forwardz[Step[n] / (n + b/a), n, z, s, nlist, zlist, op], 1/a] /;
  753.     FreeQ[{a,b}, n],        (* using (a (n + b/a)) fails when a = -1 *)
  754.  
  755. forwardz[ Step[n_] / ( n_ + 1/2 ), n_, z_, s_, nlist_, zlist_, op_ ] :>
  756.     Transform[ 2 Sqrt[z] ArcTan[z^-1], 0, Infinity ] /;
  757.      FreeQ[a,n],                        (*  [Muth, 363]  *)
  758.  
  759. forwardz[ Step[n_] / ( n_ + 1 ), n_, z_, s_, nlist_, zlist_, op_ ] :>
  760.     Transform[ -z Log[ 1 - z^-1 ], 0, Infinity ],        (*  [Muth, 363]  *)
  761.  
  762. forwardz[ Step[n_] / ( 2 n_ )!, n_, z_, s_, nlist_, zlist_, op_ ] :>
  763.     Transform[ Cosh[ Sqrt[z^-1] ], 0, Infinity ],        (*  [Muth, 363]  *)
  764.  
  765. forwardz[ (2 n_)! Step[n_] / (2^n_ n_!)^2 , n_, z_, s_, nlist_, zlist_, op_ ] :>
  766.     Transform[ Sqrt[ 1 / ( 1 - z^-1 ) ], 0, Infinity ], (*  [Muth, 364]  *)    
  767.  
  768.  
  769. (*      B.  Family of Causal Linear Phase IIR Filters            *)
  770. forwardz[ Step[n_] / ( Gamma[1 + n_] Gamma[r_ - n_] ), n_, z_,
  771.         s_, nlist_, zlist_, op_ ] :>
  772.     Block [ {},
  773.         Assuming[ Positive[r], dialogueAllFlag ];
  774.         Transform[ (1 + z^-1)^(r - 1) / Gamma[r], 0, Infinity ] ]  /;
  775.      FreeQ[r, z] && Implies[ NumberQ[N[r]], N[r > 0] ],    (*  [ASSP, 480-482]  *)    
  776.  
  777.  
  778.  
  779.  
  780. (*  IV.   P R O P E R T I E S                        *)
  781.  
  782.  
  783. (*      A.  Homogeneity (pick off constants)                *)
  784. forwardz[ c_ x_., n_, z_, s_, nlist_, zlist_, op_ ] :>
  785.     scaleZ[forwardz[x, n, z, s, nlist, zlist, op], c] /;
  786.     FreeQ[c,n] && ! ( SameQ[c,1] && SameQ[x,1] ),     (* [O & S, 67] *)
  787.  
  788. (*      B.  Additivity, resulting ROC is intersection of two ROC's    *)
  789. forwardz[ x_+y_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  790.     addZ[forwardz[x, n, z, s, nlist, zlist, op],
  791.          forwardz[y, n, z, s, nlist, zlist, op]],
  792.                              (* [O & S, 67] *)
  793.  
  794. forwardz[ (x_+y_)/c_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  795.     addZ[forwardz[x/c, n, z, s, nlist, zlist, op],
  796.          forwardz[y/c, n, z, s, nlist, zlist, op]],
  797.                              (* [O & S, 67] *)
  798.  
  799.  
  800. (*      C.  Shifts/delays --  every discrete function should be a    *)
  801. (*          function times either a Step or an Impulse, and the rule    *)
  802. (*          base already handles the Impulse case.            *)
  803. forwardz[ f_. Step[n_ + m_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  804.     scaleZ[ forwardz[(f /. n -> n - m) Step[n], n, z, s, nlist, zlist, op],
  805.         z^m ] /;
  806.     FreeQ[m, n],
  807.  
  808. forwardz[ f_. Step[m_ - n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  809.     scaleZ[ forwardz[(f /. n -> n + m) Step[-n], n, z, s, nlist, zlist, op],
  810.         z^(-m) ] /;
  811.     FreeQ[m, n],
  812.  
  813. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  814.     Block [    {n0, xnorm},
  815.         {n0, xnorm} = GetShiftFactor[x, n];
  816.         xnorm = xnorm /. ( n -> n - n0 );
  817.         scaleZ[ forwardz[xnorm, n, z, s, nlist, zlist, op], z^n0 ] ] /;
  818.     ! SameQ[ First[ GetShiftFactor[x, n] ], 0 ],
  819.  
  820.  
  821. (*      D.  Anti-causal:  x[n] --> X(z)  ===>  x[-n] --> X[1/z]    *)
  822. forwardz[ x_. Step[-n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  823.     antiCausalZ[forwardz[x Step[-n] /. n -> -n, n, z, s, nlist, zlist, op],
  824.             z],
  825.  
  826.  
  827. (*      E.  Multiplication by n^m [Muth, 227]                *)
  828. forwardz[ ZPolynomial[m_, n_] f_., n_, z_, s_, nlist_, zlist_, op_ ] :>
  829.     scaleZ[ dz[ forwardz[ f, n, z, s, nlist, zlist, op ], z, m ],
  830.         z^m ] /;
  831.     FreeQ[m, n],
  832.  
  833. forwardz[ n_^m_. x_., n_, z_, s_, nlist_, zlist_, op_ ] :>
  834.     Block [ {},
  835.                 Assuming[ m > 0, dialogueAllFlag ];
  836.         If [ dialogueAllFlag, Print[ "where ", m, " is an integer" ] ];
  837.         Zdz[ forwardz[x, n, z, s, nlist, zlist, op], z, m ] ] /;
  838.     FreeQ[m,n] && Implies[NumberQ[m], IntegerQ[m] && ( m > 0 )],
  839.  
  840.  
  841. (*      F.  Integration [Muth, 231]                    *)
  842. forwardz[ x_ Step[n_ - 1] / n_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  843.     integrateZ[scaleZ[subZ[ forwardz[x Step[n], n, z, s, nlist, zlist, op],
  844.                 Limit[x, n -> 0]],
  845.               1/z^2],
  846.            z] /;
  847.     ! InfinityQ[ Limit[x / n, n -> 0] ],
  848.  
  849.  
  850. (*      G.  Multiplication by c raised to an affine function of n,    *)
  851. (*          which covers exponential case.                *)
  852. forwardz[ c_^(d_. (b_. + a_. n_)) x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  853.     multiplyByExponential [    forwardz[x, n, z, s, nlist, zlist, op],
  854.                 c^(a d), z, c^(b d), op ] /;
  855.     FreeQ[{a,b,c,d}, n],                 (* [O & S, 67] *)
  856.  
  857.  
  858. (*      H.  Multiplication by a cosine function [Muth, 219]        *)
  859. forwardz[ Cos[b_ + w_. n_] f_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  860.     forwardz [ Cos[b] Cos[w n] f - Sin[b] Sin[w n] f,
  861.            n, z, s, nlist, zlist, op ],
  862. forwardz[ Cos[a_. n_] f_., n_, z_, s_, nlist_, zlist_, op_ ] :>
  863.     Block [    {trans},
  864.         trans = forwardz[f, n, z, s, nlist, zlist, op];
  865.         scaleZ [ addZ [ substituteforZ[trans, z, Exp[I a] z],
  866.                 substituteforZ[trans, z, Exp[-I a] z] ],
  867.              1/2] ] /;
  868.     FreeQ[a,n],
  869.  
  870.  
  871. (*      I.  Multiplication by a sine function [Muth, 219]        *)
  872. forwardz[ Sin[b_ + w_. n_] f_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  873.     forwardz [ Sin[b] Cos[w n] f + Cos[b] Sin[w n] f,
  874.            n, z, s, nlist, zlist, op ],
  875. forwardz[ Sin[a_. n_] f_., n_, z_, s_, nlist_, zlist_, op_ ] :>
  876.     Block [    {trans},
  877.         trans = forwardz[f, n, z, s, nlist, zlist, op];
  878.         scaleZ [ subZ [ substituteforZ[trans, z, Exp[I a] z],
  879.                 substituteforZ[trans, z, Exp[-I a] z] ],
  880.              I/2] ] /;
  881.     FreeQ[a,n],
  882.  
  883.  
  884. (*      J.  Conjugation:  Z{ Conj[x[n]] } --> Conj[ X ( Conj[z] ) ]    *)
  885. forwardz[ Conjugate[x_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  886.     conjZ[forwardz[x, n, z, s, nlist, zlist, op], z],
  887.                              (* [O&S, 67]  *)
  888.  
  889.  
  890.  
  891.  
  892. (*  V.    D S P     S T R U C T U R E S                    *)
  893.  
  894.  
  895. (*      -.  An operator independent of n---  take z-transform of f    *)
  896. forwardz[ operator_[params__][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  897.     propagateOperator[ forwardz[f, n, z, s, nlist, zlist, op],
  898.                operator[params] ] /;
  899.     FreeQ[{params}, n],
  900.  
  901.  
  902. (*      A.  Convolution                        *)
  903. forwardz[ Convolve[n_][x1_, x2_, rest__], n_, z_, s_, nlist_, zlist_, op_ ] :>
  904.     multZ [ forwardz[x1, n, z, s, nlist, zlist, op],
  905.         forwardz[Convolve[n][x2, rest], n, z, s, nlist, zlist, op] ],
  906.  
  907. forwardz[ Convolve[n_][x1_, x2_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  908.     multZ [ forwardz[x1, n, z, s, nlist, zlist, op],
  909.         forwardz[x2, n, z, s, nlist, zlist, op] ],
  910.  
  911. forwardz[ Convolve[nconv_List][x1_, x2_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  912.     convolveZ[ Convolve[Complement[nconv, {n}]], 
  913.            forwardz[x1, n, z, s, nlist, zlist, op],
  914.            forwardz[x2, n, z, s, nlist, zlist, op] ] /;
  915.     MemberQ[nconv, n],
  916.  
  917.  
  918. (*      B.  Difference equations [Muth, 224]                *)
  919. forwardz[ Difference[m_, n_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  920.     Block [ {},
  921.         Assuming[ m > 0, dialogueAllFlag ];
  922.         If [ dialogueAllFlag, Print[ "where ", m, " is an integer" ] ];
  923.         scaleZ[ forwardz[f, n, z, s, nlist, zlist, op],
  924.             ( 1 - z^-1 ) ^ m ] ] /;
  925.     FreeQ[m,n] && Implies[NumberQ[m], IntegerQ[m] && m > 0],
  926.  
  927. (*      C.  Downsampling                        *)
  928.  
  929. (*          1. Downsampling operator [Crochiere & Rabiner, 34]    *)
  930. forwardz[ Downsample[m_,n_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  931.     Block [ {},
  932.         If [ dialogueAllFlag,
  933.              Print[ "assuming ", m, " is an integer" ] ];
  934.         downsampleZ[ forwardz[f, n, z, s, nlist, zlist, op], z, m ] ] /;
  935.     FreeQ[m,n] && Implies[ NumberQ[m], IntegerQ[m] ] ,
  936.  
  937. (*          2. Rewrite functions that are really downsampled        *)
  938. (*               This relies on the function ScalingFactor which works  *)
  939. (*          best after an expression has been fully expanded.     *)
  940. forwardz[ f_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  941.     Block [    {m},
  942.         m = computeDownsamplingFactor[f, n];
  943.         If [ dialogueAllFlag && ! IntegerQ[m],
  944.              Print[ "assuming ", m, " is an integer" ] ];
  945.         forwardz[ Downsample[m, n][ f /. n -> (n/m) ],
  946.               n, z, s, nlist, zlist, op ] ] /;
  947.     reallyDownsampledQ[f, n],
  948.  
  949.  
  950. (*      D.  Digital FIR filters.                    *)
  951. forwardz[ FIR[n_, h_, firop___], n_, z_, s_, nlist_, zlist_, op_ ] :>
  952.     forwardz[SequenceToFunction[ToList[h], n],
  953.          n, z, s, nlist, zlist, op],
  954.  
  955. forwardz[ FIR[n_, h_, firop___] [ x__ ], n_, z_, s_, nlist_, zlist_, op_ ] :>
  956.     multZ [ forwardz[FIR[n, h, firop], n, z, s, nlist, zlist, op],
  957.         forwardz[x, n, z, s, nlist, zlist, op] ],
  958.  
  959. (*      E.  Digital IIR filters.                    *)
  960. (*          Region of convergence is incorrect.            *)
  961. forwardz[ IIR[n_, a_List, iirop___], n_, z_, s_, nlist_, zlist_, op_ ] :>
  962.     Block [    {denom, len, poles},
  963.         len = Length[a];
  964.         denom = a[[1]] -
  965.             Sum[a[[index+1]] z^(- index), {index, 1, len - 1}];
  966.         poles = GetRootList[denom, z];
  967.         { 1 / denom, Max[Abs[poles]], Infinity } ] /;
  968.     VectorQ[a],
  969.  
  970. forwardz[ IIR[n_, a_, iirop___] [ x__ ], n_, z_, s_, nlist_, zlist_, op_ ] :>
  971.     multZ [ forwardz[IIR[n, a, iirop], n, z, s, nlist, zlist, op],
  972.         forwardz[x, n, z, s, nlist, zlist, op] ],
  973.  
  974. forwardz[ IIRFunction[n_, a_, x_, h_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  975.     multZ [ forwardz[IIR[n, a], n, z, s, nlist, zlist, op],
  976.         forwardz[x, n, z, s, nlist, zlist, op] ],
  977.  
  978. (*      F.  Imaginary part of a sequence [O&S, 67]            *)
  979. forwardz[ Im[x_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  980.     Block [    {trans},
  981.         trans = forwardz[x, n, z, s, nlist, zlist, op];
  982.         scaleZ [ addZ [ trans,
  983.                 substituteforZ[trans, z, Conjugate[z]] ],
  984.              1/2] ],
  985.  
  986. (*      G.  Periodic sequence with period k samples [Muth, 232]    *)
  987. forwardz[ Periodic[k_,n_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  988.     Block [    {fk, ntemp},
  989.         Assuming[ k > 0, dialogueAllFlag ];
  990.         If [ dialogueAllFlag && ! IntegerQ[k],
  991.              Print[ "where ", k, " is an integer" ] ];
  992.  
  993.         fk = If [ NumberQ[k],
  994.               SequenceToFunction[ Table[f /. n -> ntemp,
  995.                             {ntemp, 0, k-1}],
  996.                           n ],
  997.               f Pulse[k, n] ];
  998.  
  999.         scaleZ [ forwardz[fk, n, z, s, nlist, zlist, op],
  1000.              1 / ( 1 - z^(-Abs[k]) ) ] ] /;
  1001.     FreeQ[k,n] && Implies[NumberQ[k], IntegerQ[k] && k > 0],
  1002.  
  1003. (*      H.  Real part of a sequence [O&S, 67]                *)
  1004. forwardz[ Re[x_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1005.     Block [    {trans},
  1006.         trans = forwardz[x, n, z, s, nlist, zlist, op];
  1007.         scaleZ [ addZ [ trans,
  1008.                 substituteforZ[trans, z, Conjugate[z]] ],
  1009.              -I/2] ],
  1010.  
  1011. (*      I.  Reverse operator    ?ROC?                    *)
  1012. forwardz[ Rev[n_][x_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1013.     antiCausalZ[forwardz[x, n, z, s, nlist, zlist, op], z],
  1014.  
  1015.  
  1016. (*      J.  Shift operator                        *)
  1017. forwardz[ Shift[m_,n_][x_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1018.     Block [ {},
  1019.         If [ dialogueAllFlag && ! IntegerQ[m],
  1020.              Print[ "assuming ", m, " is an integer" ] ];
  1021.         scaleZ[forwardz[x, n, z, s, nlist, zlist, op], z^(-m)] ] /;
  1022.     FreeQ[m,n] && Implies[NumberQ[m], IntegerQ[m]],
  1023.  
  1024.  
  1025. (*      K.  Signum function                        *)
  1026. forwardz[ f_. Sign[g_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1027.     forwardz[ f Step[g] - f Step[-g], n, z, s, nlist, zlist, op ] /;
  1028.     ! FreeQ[f, n],
  1029.  
  1030.  
  1031. (*      L.  Summation                            *)
  1032. forwardz[ Summation[i_,0,n_,1][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1033.     scaleZ[ forwardz[f, n, z, s, nlist, zlist, op], 1 / ( 1 - z^-1 ) ] /;
  1034.     FreeQ[i, n],                (* [Muth, 255] *)
  1035.  
  1036. forwardz[ Summation[i_,il_,iu_,inc_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1037.     forwardz[ Summation[i, 0, Expand[iu - il], inc][f /. i -> i + il],
  1038.           n, z, s, nlist, zlist, op ] /;
  1039.     FreeQ[{i, inc}, n] && (! FreeQ[il, n]) && (! FreeQ[iu, n]) &&
  1040.       FreeQ[Expand[iu - il], n],
  1041.  
  1042. (*
  1043. forwardz[ Summation[i_,il_,iu_,inc_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1044.     propagateOperator[ forwardz[f, n, z, s, nlist, zlist, op],
  1045.                Summation[i, il, iu, inc] ] /;
  1046.     FreeQ[{i, il, iu, inc}, n],
  1047.  *)
  1048.  
  1049.  
  1050. (*      M.  Upsampling [Crochiere & Rabiner, 36]            *)
  1051. forwardz[ Upsample[m_,n_][f_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1052.     Block [ {},
  1053.         If [ dialogueAllFlag && ! IntegerQ[m],
  1054.              Print[ "assuming ", m, " is an integer" ] ];
  1055.         upsampleZ[ forwardz[f, n, z, s, nlist, zlist, op], z, m ] ] /;
  1056.     FreeQ[m,n] && Implies[ NumberQ[m], IntegerQ[m] && ( m > 0 ) ],
  1057.  
  1058.  
  1059.  
  1060.  
  1061. (*  V.     S T R A T E G I E S                        *)
  1062.  
  1063.  
  1064. (*       A.  Handle affine step functions.                *)
  1065. forwardz[ f_. Step[k_ n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1066.     Block [ {},
  1067.         If [ dialogueAllFlag && ! IntegerQ[k],
  1068.              Print[ "assuming ", k, " is an integer" ] ];
  1069.         forwardz[ f Step[n], n, z, s, nlist, zlist, op ] ] /;
  1070.     Implies[ NumberQ[k], IntegerQ[k] ],
  1071.  
  1072.  
  1073. (*       A.  Remove any time-dependent Abs functions            *)
  1074. forwardz[ f_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1075.     forwardz[ absDialogue[f, n, op], n, z,
  1076.           SetStateField[s, stepfield, False],
  1077.           nlist, zlist, op ] /;
  1078.     GetStateField[s, stepfield] && ! FreeQ[ f, Abs[n] ],
  1079.  
  1080.  
  1081. (*       B.  Collect exponential terms                 *)
  1082. forwardz[ f_. a_^(t_. n_ + k_.) / b_^(u_. n_ + l_.), n_, z_,
  1083.         s_, nlist_, zlist_, op_ ] :>
  1084.     forwardz[ (a^t/b^u)^n f a^k/b^l, n, z, s, nlist, zlist, op ],
  1085.  
  1086.  
  1087. (*       C.  Handle functions which "blow up" at origin        *)
  1088. forwardz[ x_ Step[n_] / n_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1089.     forwardz[ Limit[x / n, n -> 0] Impulse[n] + x Step[n-1] / n, n, z,
  1090.           s, nlist, zlist, op ] /;
  1091.     ( Limit[x, n -> 0] == 0 ),
  1092.  
  1093.  
  1094. (*       D.  Expand out product terms like (n + 1) (n + 2) ...    *)
  1095. forwardz[ x_Times, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1096.     forwardz [ Distribute[x], n, z, s, nlist, zlist, op ] /;
  1097.     ! SameQ[x, Distribute[x]],
  1098.  
  1099.  
  1100. (*       E.  Factor denominator                    *)
  1101. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1102.     forwardz [ Numerator[x] / Factor[Denominator[x]], n, z,
  1103.            SetStateField[s, factorfield, False],
  1104.            nlist, zlist, op ] /;
  1105.     GetStateField[s, factorfield] && RationalFunctionQ[x, n],
  1106.  
  1107.  
  1108. (*       F.  Expand out numerator terms                *)
  1109. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1110.     forwardz [ Expand[x], n, z,
  1111.            SetStateField[s, expandfield, False],
  1112.            nlist, zlist, op ] /;
  1113.     GetStateField[s, expandfield] && ! SameQ[x, Expand[x]],
  1114.  
  1115.  
  1116. (*       G.  Expand out numerator and denominator terms        *)
  1117. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1118.     forwardz [ ExpandAll[x], n, z,
  1119.            SetStateField[s, expandallfield, False],
  1120.            nlist, zlist, op ] /;
  1121.     GetStateField[s, expandallfield] && ! SameQ[x, ExpandAll[x]],
  1122.  
  1123.  
  1124. (*         H.  Use the definition                    *)
  1125. forwardz[ x_ Step[n_], n_, z_, s_, nlist_, zlist_, op_ ] :>
  1126.     applyDefinition[x, n, z, s, nlist, zlist, op] /;
  1127.     GetStateField[s, definitionfield] && Replace[Definition, op],
  1128.  
  1129.  
  1130. (*       I.  Two-sided transform                    *)
  1131. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1132.     Block [    {state, trans},
  1133.         state = SetStateField[s, stepfield, False];
  1134.         trans = MyZTransform[ x Step[n] + x Step[-n - 1],
  1135.                       n, z, state, nlist, zlist, op ];
  1136.         If [ TrueQ[ZForm[trans] && TheFunction[trans] != 0],
  1137.              If [ InformUserQ[op],
  1138.                   Message[Transform::twosided, x] ];
  1139.              trans,
  1140.              forwardz[ x, n, z, state, nlist, zlist, op ] ] ] /;
  1141.     GetStateField[s, stepfield],
  1142.  
  1143.  
  1144. (*       J.  Put all signal processing objects into mathematical form    *)
  1145. forwardz[ x_, n_, z_, s_, nlist_, zlist_, op_ ] :>
  1146.     Block [    {newx, state},
  1147.         newx = ToDiscrete [ TheFunction[x] ];
  1148.  
  1149.         state = If [ SameQ[newx, x], s, initZstate[] ];
  1150.         state = SetStateField[state, thefunfield, False];
  1151.         state = SetStateField[state, stepfield, False];
  1152.  
  1153.         forwardz [ newx, n, z, state, nlist, zlist, op ] ] /;
  1154.     GetStateField[s, thefunfield]
  1155.  
  1156. }
  1157.  
  1158.  
  1159. (*  E N D     R U L E S  *)
  1160.  
  1161.  
  1162.  
  1163. (*  E N D     P A C K A G E  *)
  1164.  
  1165.  
  1166. End[]
  1167. EndPackage[]
  1168.  
  1169. If [ TrueQ[ $VersionNumber >= 2.0 ],
  1170.      On[ General::spell ];
  1171.      On[ General::spell1 ] ];
  1172.  
  1173.  
  1174. (*  H E L P     I N F O R M A T I O N  *)
  1175.  
  1176. Combine[ SPfunctions, { ZTransform } ]
  1177. Protect[ ZTransform ]
  1178.  
  1179.  
  1180. (*  E N D I N G     M E S S A G E  *)
  1181.  
  1182. Print["The forward z-transform rules have been loaded."]
  1183. Null
  1184.